<!--
 * @Author: your name
 * @Date: 2020-09-07 10:23:36
 * @LastEditTime: 2021-10-14 22:09:21
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: /gatt/src/modules/front/pages/Gatt/components/GattDate/index.vue
-->
<template>
  <div class="gatt-date">
    <!-- 甘特主题内容 -->
    <gatt-main
      v-if="days.length && computedList.length"
      :allDays="allDays"
      :days="days"
      :showFixdTopMonth="showFixdTopMonth"
      :fixdTopMonth="fixdTopMonth"
      :tableScrollTop="tableScrollTop"
      :fieldsAttr="fieldsAttr"
      :computedList="computedList"
      @lineMousedown="lineMousedown"
      @thunkMouseup="thunkMouseup"
      :currentDaySize="currentDaySize"
      @leftCurDragMounsedown="leftCurDragMounsedown"
      @rightCurDragMounsedown="rightCurDragMounsedown"
      @lineMouseenter="lineMouseenter"
      @lineMouseleave="lineMouseleave"
      @handlerBGScroll="handlerBGScroll"
    ></gatt-main>
    <!-- 时间模式选择 -->
    <div class="gatt-date-toolTip">
      <el-dropdown trigger="click">
        <span class="base">
          {{ currentDaySize.label }}
          <i class="el-icon-arrow-down el-icon--right"></i>
        </span>
        <el-dropdown-menu
          slot="dropdown"
          :style="{ left: this.dropdownLeft + 'px !important' }"
        >
          <el-dropdown-item
            v-for="item in options.dayModeSize"
            :key="item.value + 'ck'"
            @click.native="handleSetDaySize(item)"
            >{{ item.label }}</el-dropdown-item
          >
        </el-dropdown-menu>
      </el-dropdown>
      <div @click="handleGoToday" class="today base" >今天</div>
    </div>
    <transition name="el-zoom-in-center">
      <div
        class="projectMsg"
        v-if="isShowMsg"
        :style="{
          left: currentProjectMsg.left + 'px',
          top: currentProjectMsg.top + 'px'
        }"
      >
        <template v-for="(val, key) in currentProjectMsg">
          <div v-if="key !== 'left' && key !== 'top'" class="lineMsg" :key="key">
            <span v-if="key === 'name'" class="projectName">{{ val.value }}</span>
            <template v-else>
              <span class="title">{{val.label}}:</span>
              <span>{{ val.value }}</span>
            </template>
          </div>
        </template>
      </div>
    </transition>
  </div>
</template>

<script>
import GattMain from './components/GattMain.vue'
export default {
  name: 'GattDate',
  components: {
    GattMain
  },
  computed: {
    dropdownLeft () {
      return window.innerWidth - 30
    },
    // 当前年份
    currentYear () {
      return new Date().getFullYear()
    },
    // 当前月份
    currentMonth () {
      return new Date().getMonth() + 1
    },
    // 当前日
    currentDay () {
      return new Date().getDate()
    }
  },
  props: {
    rightLineX: {
      type: Number,
      default: () => 300
    },
    tableScrollTop: {
      type: Number,
      default: () => 0
    },
    currentRow: {
      type: Object,
      default: () => null
    }
  },
  data () {
    return {
      // 整体开始时间
      startTime: 1600473600000,
      // 整体结束时间
      endTime: 1600473600000,
      // 近三年的所有年月日(开始至结束时间与近三年的并集)
      allDays: [],
      // 所有的天数
      days: [],
      // 月数
      monthArr: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
      // 当前hover的项目起止时间
      currentLineDay: {
        start: 0,
        end: 0
      },
      // 当前的时间大小
      currentDaySize: {
        label: '按天',
        value: 40,
        mode: 'day'
      },
      showFixdTopMonth: false,
      fixdTopMonth: '',
      // 是否显示信息
      isShowMsg: false,
      // 当前hover的项目信息
      currentProjectMsg: {},
      isHover: false,
      // 定时器 左侧拖拽
      timer: null,
      options: {
        dayModeSize: [
          {
            label: '按天',
            value: 40,
            mode: 'day'
          },
          {
            label: '按周',
            value: 18,
            mode: 'week'
          },
          {
            label: '月度',
            value: 8,
            mode: 'month'
          },
          {
            label: '季度',
            value: 4,
            mode: 'quarter'
          },
          {
            label: '半年',
            value: 1,
            mode: 'halfYear'
          }
        ]
      },
      // 出口的线与连线之间的diff间距left
      fromLeftDiff: 29,
      // 出口的线与连线之间的diff间距top
      fromTopDiff: 26,
      // 入口的线与箭头之间的diff间距left
      targetLeftDiff: 29,
      // 前置依赖-出口的线与连线之间的diff间距left
      reqFromLeftDiff: 29,
      // 前置依赖-出口的线与连线之间的diff间距top
      reqFromTopDiff: 26,
      // 前置依赖出口出连接线的默认宽度
      reqFromLinkWidth: 40,
      // 项目数据，树形扁平化的平行数据
      list: [],
      computedList: [],
      fieldsAttr: {}
    }
  },
  watch: {
    currentDaySize (newValue, oldValue) {
      this.list.forEach(item => {
        item.left = (item.left / oldValue.value) * newValue.value
        item.widthMe = item.widthChild =
          (item.widthMe / oldValue.value) * newValue.value
      })
    },
    list: {
      deep: true,
      handler () {
        const arr = []
        this.list.forEach((item, index) => {
          const left = item.left - this.fromLeftDiff
          const top = item.top + this.fromTopDiff
          if (item.depends && item.depends.length) {
            item.depends.forEach((dependItem, _index) => {
              const targetItem = this.list.find(i => i.id === dependItem.id)
              const inLeft = ~~targetItem.left
              const inTop = ~~targetItem.top
              const w = inLeft - left - this.targetLeftDiff
              const h = inTop - top
              dependItem.left = inLeft
              // 链接线的left，top width, height
              dependItem.linkLeft = left
              dependItem.linkTop = inTop
              dependItem.linkWidth = w
              dependItem.linkHeight = h
            })
          }
          if (item.requireChild && item.requireChild.length) {
            item.requireChild.forEach((dependItem, _index) => {
              const targetItem = this.list.find(i => i.id === dependItem.id)
              let linkTopWidth = 40
              const inLeft = ~~targetItem.left
              const inTop = ~~targetItem.top
              let outLeft = item.left + item.widthMe
              if (dependItem.advanceDays && ~~dependItem.advanceDays !== 0) {
                linkTopWidth = ~~dependItem.advanceDays * this.currentDaySize.value + 40
                outLeft = outLeft - ~~dependItem.advanceDays * this.currentDaySize.value
              }
              const w = inLeft - outLeft
              const h = inTop - (item.top + this.reqFromTopDiff)
              dependItem.left = inLeft
              // 链接线的left，top width, height
              dependItem.linkLeft = outLeft - this.reqFromLeftDiff
              dependItem.linkTop = inTop
              dependItem.linkWidth = w
              dependItem.linkHeight = h
              dependItem.linkTopWidth = linkTopWidth
            })
          }
          arr.push(item)
        })
        this.computedList = arr
      }
    }
  },
  mounted () {
    // this.init()
    document.addEventListener('scroll', this.handleScroll)
  },
  beforeDestroy () {
    window.removeEventListener('scroll', this.handleScroll)
    document.onmousemove = document.onmouseup = null
  },
  methods: {
    init (list, fieldsAttr) {
      this.list = list
      this.fieldsAttr = fieldsAttr
      this.getAllDate()
    },
    // 左侧拖拽增加
    /**
     * @param  {String} domId ref/id
     * @param  {Object} e $event
     * @param  {Number} id id
     * @param  {Number} parentId parentId
     * @param  {Number} index index
     */
    leftCurDragMounsedown (domId, e, id, parentId, index, item) {
      const line = document.getElementById(domId)
      const cx = e.pageX
      let result
      let result1
      let z = 0
      let x = 0
      let addwidth
      let timers
      // 获取设置linkdom
      this.getLinkDom(item)
      document.onmousemove = event => {
        if (
          event.clientX <= this.rightLineX + 80 &&
          event.pageX >= this.rightLineX + 80
        ) {
          if (!this.timer) {
            this.timer = window.setInterval(() => {
              z = window.scrollX - this.currentDaySize.value
              // window.scrollTo(z, 0);
              window.scrollTo({
                top: 0,
                left: z,
                behavior: 'smooth'
              })
              addwidth = cx - event.pageX
            }, 50)
          }
        } else if (event.clientX >= window.innerWidth - 80) {
          if (!timers) {
            timers = window.setInterval(() => {
              x = window.scrollX + this.currentDaySize.value
              // window.scrollTo(x, 0);
              window.scrollTo({
                top: 0,
                left: x,
                behavior: 'smooth'
              })
              addwidth = -(event.pageX - cx)
            }, 50)
          }
        } else {
          window.clearInterval(this.timer)
          window.clearInterval(timers)
          this.timer = null
          timers = null
          if (event.pageX <= this.rightLineX) {
            addwidth = -(this.rightLineX - 2 - cx)
          } else {
            addwidth = -(event.pageX - cx)
          }
        }
        result = this.computedList[index].widthMe + addwidth
        result1 = this.computedList[index].left - addwidth
        if (result <= this.currentDaySize.value) {
          result = this.currentDaySize.value
          result1 =
            this.computedList[index].left +
            this.computedList[index].widthMe -
            this.currentDaySize.value
        } else if (result1 <= 0) {
          result1 = 0
        }
        if (item.depends && item.depends.length) {
          // 拖拽有子任务选项场景
          this.handleDragSetLinkLine(result1, addwidth, item.depends)
        }
        if (item.dependPid) {
          // 拖拽有父级依赖选项场景， 依据依赖id找出依赖主体的连接线并改变宽度
          let linkWidth = 0
          const dependPid = item.dependPid
          const dependPitem = this.computedList.find(from => from.id === dependPid)
          if (result1 <= dependPitem.left) {
            // 移动的左边距未超出父级的左边距时 不能过界
            result1 = dependPitem.left
            linkWidth = 0
            result = this.computedList[index].widthMe + (item.left - result1)
          } else {
            linkWidth = result1 - (dependPitem.left - this.fromLeftDiff) - this.targetLeftDiff
          }
          dependPitem.depends.map(pItem => {
            if (pItem.id === item.id) {
              pItem.linkDom.style.width = linkWidth + 'px'
            }
          })
        }
        // 拖拽有前置依赖选项时
        if (item.requireId) {
          let linkWidth = 0
          const requireItem = this.computedList.find(req => req.id === item.requireId)
          const linkItem = requireItem.requireChild.find(link => link.id === item.id)
          let outLeft = requireItem.left + requireItem.widthMe
          if (linkItem.advanceDays && ~~linkItem.advanceDays !== 0) {
            outLeft = outLeft - ~~linkItem.advanceDays * this.currentDaySize.value
          }
          if (result1 <= outLeft) {
            result1 = outLeft
            result = item.widthMe + (item.left - result1)
            linkWidth = 0
          } else {
            linkWidth = result1 - outLeft
          }
          linkItem.linkDom.style.width = linkWidth + 'px'
        }
        this.computedList[index].widthChild = result
        line.style.width = result + 'px'
        line.style.left = result1 + 'px'
        // this.lineMouseover(domId, e, id, parentId, index)
        this.lineMouseleave(e, true)
      }
      document.onmouseup = events => {
        if (!result) {
          document.onmousemove = document.onmouseup = null
          return
        }
        window.clearInterval(this.timer)
        window.clearInterval(timers)
        this.timer = null
        timers = null
        result =
          Math.round(result / this.currentDaySize.value) *
          this.currentDaySize.value
        // 由于存在拖动的步长所以不足步长等场景会进行四舍五入，对应的连接线也要处理
        result1 =
          Math.round(parseInt(line.style.left) / this.currentDaySize.value) *
          this.currentDaySize.value
        // 拖拽父任务场景
        if (item.depends && item.depends.length) {
          this.handleDragSetLinkLine(result1, addwidth, item.depends, true)
        }
        // 拖拽有前置依赖选项时
        if (item.requireId) {
          let linkWidth = 0
          const requireItem = this.computedList.find(req => req.id === item.requireId)
          const linkItem = requireItem.requireChild.find(link => link.id === item.id)
          let outLeft = requireItem.left + requireItem.widthMe
          if (linkItem.advanceDays && ~~linkItem.advanceDays !== 0) {
            outLeft = outLeft - ~~linkItem.advanceDays * this.currentDaySize.value
          }
          if (result1 <= outLeft) {
            result1 = outLeft
            result = item.widthMe + (item.left - result1)
            linkWidth = 0
          } else {
            linkWidth = result1 - outLeft
          }
          linkItem.linkWidth = linkWidth
          linkItem.linkDom.style.width = linkWidth + 'px'
        }
        this.computedList[index].widthMe = result
        this.computedList[index].widthChild = result
        this.computedList[index].left = result1
        line.style.width = result + 'px'
        line.style.left = result1 + 'px'
        this.checkIsin(domId, events, id, parentId, index)
        if (parentId) {
          // 存在父级的时候 需要改变group的宽度和left
          this.setGroupWidth(parentId)
        }
        document.onmousemove = document.onmouseup = null
      }
    },
    // 右侧边缘增加
    /**
     * @param  {String} dom ref
     * @param  {Object} e $event
     * @param  {Number} id id
     * @param  {Number} parentId parentId
     * @param  {Number} index index
     */
    rightCurDragMounsedown (dom, e, id, parentId, index, item) {
      const line = document.getElementById(dom)
      const cx = e.pageX
      let result
      let z = 0
      let x = 0
      let wx = window.scrollX
      let addwidth
      let timers
      // 获取linkdom
      if (item.requireChild && item.requireChild.length) {
        // 拖拽的是有前置依赖任务选项场景时候 获取连线dom
        item.requireChild.forEach(dep => {
          if (!dep.linkDom) {
            dep.linkDom = document.getElementById(`${item.id}-link-${dep.id}`)
          }
          if (!dep.depLineDom) {
            dep.depLineDom = document.getElementById(`line${dep.id}`)
          }
        })
      }
      document.onmousemove = event => {
        if (event.clientX >= window.innerWidth - 80) {
          if (!this.timer) {
            z = 0
            wx = window.scrollX
            this.timer = window.setInterval(() => {
              z = z + this.currentDaySize.value
              // window.scrollTo(z + wx, 0);
              window.scrollTo({
                top: 0,
                left: z + wx,
                behavior: 'smooth'
              })
              addwidth = event.pageX - cx + z
            }, 50)
          }
        } else if (event.clientX <= this.rightLineX + 80) {
          if (!timers) {
            timers = window.setInterval(() => {
              x = window.scrollX - this.currentDaySize.value
              // window.scrollTo(x, 0);
              window.scrollTo({
                top: 0,
                left: x,
                behavior: 'smooth'
              })
              addwidth = event.pageX - cx
            }, 50)
          }
        } else {
          window.clearInterval(this.timer)
          window.clearInterval(timers)
          this.timer = null
          timers = null
          addwidth = event.pageX - cx
        }
        result = this.computedList[index].widthMe + addwidth
        if (
          result + parseInt(line.style.left) >=
          this.days.length * this.currentDaySize.value
        ) {
          result =
            this.days.length * this.currentDaySize.value -
            parseInt(line.style.left)
        }
        line.style.width = result + 'px'
        this.computedList[index].widthChild = result
        // console.log(line.style.width);
        if (result <= this.currentDaySize.value) {
          result = this.currentDaySize.value
          line.style.width = result + 'px'
          this.computedList[index].widthMe = result
          this.computedList[index].widthChild = result
        }
        if (item.requireChild && item.requireChild.length) {
          // 右拖拽前置依赖的父级选项时
          item.requireChild.forEach(reqItem => {
            const targetItem = this.computedList.find(req => req.id === reqItem.id)
            let linkWidth = 0
            if (item.left + result >= targetItem.left) {
              linkWidth = 0
              // 如果前置依赖父级右移过了子集的左边距则子集跟随右移
              reqItem.depLineDom.style.left = result + item.left + 'px'
            } else {
              linkWidth = targetItem.left - (item.left + result)
              if (item.left + result >= targetItem.left) {
                reqItem.depLineDom.style.left = result + item.left + 'px'
              } else {
                reqItem.depLineDom.style.left = targetItem.left + 'px'
              }
            }
            reqItem.linkDom.style.left = result + item.left - this.reqFromLeftDiff + 'px'
            reqItem.linkDom.style.width = linkWidth + 'px'
          })
        }
        // this.lineMouseover(dom, e, id, parentId, index)
        this.lineMouseleave(e, true)
      }
      document.onmouseup = events => {
        if (!result) {
          document.onmousemove = document.onmouseup = null
          return
        }
        window.clearInterval(this.timer)
        window.clearInterval(timers)
        this.timer = null
        timers = null
        result =
          Math.round(result / this.currentDaySize.value) *
          this.currentDaySize.value
        this.computedList[index].widthMe = result
        this.computedList[index].widthChild = result
        if (item.requireChild && item.requireChild.length) {
          // 右拖拽前置依赖的父级选项时
          item.requireChild.forEach(reqItem => {
            const targetItem = this.computedList.find(req => req.id === reqItem.id)
            let linkWidth = 0
            if (item.left + result >= targetItem.left) {
              linkWidth = 0
              // 如果前置依赖父级右移过了子集的左边距则子集跟随右移
              reqItem.depLineDom.style.left = result + item.left + 'px'
              targetItem.left = result + item.left
            } else {
              linkWidth = targetItem.left - (item.left + result)
            }
            reqItem.linkDom.style.left = result + item.left - this.reqFromLeftDiff + 'px'
            reqItem.linkDom.style.width = linkWidth + 'px'
          })
        }
        line.style.width = result + 'px'
        this.checkIsin(dom, events, id, parentId, index)
        if (parentId) {
          // 存在父级的时候 需要改变group的宽度和left
          this.setGroupWidth(parentId)
        }
        document.onmousemove = document.onmouseup = null
      }
    },
    // 设置连接线left和width已经子任务line的left
    handleDragSetLinkLine (result1, addwidth, depends, isMouseDown) {
      // 拖拽的是有依赖子任务选项场景时候
      depends.forEach(dep => {
        let linkWidth = 0
        let linkLeft = 0
        linkLeft = result1 - this.fromLeftDiff
        if (addwidth < 0) {
          // 往右拖了，依赖子集统一右移，连线的距离是不变的
          linkWidth = dep.left - linkLeft - this.targetLeftDiff
          // 移动到子任务左侧临界点时
          if (result1 >= dep.left || ((dep.left - result1) > 0 && (dep.left - result1) < this.currentDaySize.value / 2)) {
            // 当父级拖动过了子任务的left边界时 （此时有拖动距离小于1/2步长的特殊场景）
            linkWidth = 0
            // 设置数据left
            dep.left = result1
            this.list.forEach(item => {
              if (item.id === dep.id) {
                item.left = result1
              }
            })
            dep.depLineDom.style.left = result1 + 'px'
          }
        } else {
          // 往左边拖的时候，改变连线的距离width
          linkWidth = dep.left - linkLeft - this.targetLeftDiff
        }
        if (isMouseDown) {
          // 鼠标按起时更改数据
          dep.linkWidth = linkWidth
          dep.linkLeft = linkLeft
        }
        dep.linkDom.style.width = linkWidth + 'px'
        // 连接线left与拖拽的left是一致的
        dep.linkDom.style.left = linkLeft + 'px'
      })
    },
    // 获取设置linkdom
    getLinkDom (item) {
      if (item.depends && item.depends.length) {
        // 拖拽的是有依赖子任务选项场景时候 获取连线dom
        item.depends.forEach(dep => {
          if (!dep.linkDom) {
            dep.linkDom = document.getElementById(`${item.id}-link-${dep.id}`)
          }
          if (!dep.depLineDom) {
            dep.depLineDom = document.getElementById(`line${dep.id}`)
          }
        })
      }
      if (item.dependPid) {
        // 拖拽的是子任务场景 获取连线dom
        this.computedList.forEach(pItem => {
          if (pItem.id === item.dependPid) {
            pItem.depends.forEach(dep => {
              if (dep.id === item.id) {
                if (!dep.linkDom) {
                  dep.linkDom = document.getElementById(`${item.dependPid}-link-${item.id}`)
                }
                if (!dep.depLineDom) {
                  dep.depLineDom = document.getElementById(`line${item.id}`)
                }
              }
            })
          }
        })
      }
      if (item.requireId) {
        // 拖拽有前置依赖的选项线时
        this.computedList.forEach(pItem => {
          if (pItem.id === item.requireId) {
            pItem.requireChild.forEach(dep => {
              if (dep.id === item.id) {
                if (!dep.linkDom) {
                  dep.linkDom = document.getElementById(`${item.requireId}-link-${item.id}`)
                }
                if (!dep.depLineDom) {
                  dep.depLineDom = document.getElementById(`line${item.id}`)
                }
              }
            })
          }
        })
      }
    },
    // 滑动进度条事件
    thunkMouseup (per, e, id, parentId) {
      this.list.forEach(item => {
        if (item.id === id) {
          item.per = per
        }
      })
      if (parentId) {
        this.setGroupPer(parentId)
      }
      const cindex = this.computedList.findIndex(z => {
        return z.id === id
      })
      this.checkIsin(`line${id}`, e, id, parentId, cindex)
    },
    // 根据父级id设置分组百分比
    setGroupPer (id, lists) {
      const that = this
      fn(id, lists)
      function fn (id, lists) {
        let z
        if (lists) {
          z = lists.find(o => {
            return o.id === id
          })
        } else {
          z = that.list.find(o => {
            return o.id === id
          })
        }
        const childrenArr = []
        that.list.forEach(item => {
          if (item.parentId === id) {
            childrenArr.push(item)
          }
        })
        let count = 0
        const length = childrenArr.length
        childrenArr.forEach(item => {
          count = count + (item.per / 100) * (1 / length)
        })
        z.per = Math.round(count * 100)
        if (z.parentId) {
        //  如果还有父级
          fn(z.parentId, lists)
        }
      }
    },
    // 每一行拖拽
    /**
     * @param  {String} dom ref
     * @param  {Object} events $event
     * @param  {Number} id id
     * @param  {Number} parentId parentId
     * @param  {Number} index index
     */
    lineMousedown (dom, e, id, parentId, index, item) {
      const line = document.getElementById(dom)
      const cp = e.pageX
      let result
      let z = 0
      let left
      let newWith = 0
      // 获取设置linkdom
      this.getLinkDom(item)
      if (item.requireChild && item.requireChild.length) {
        // 拖拽的是有前置依赖任务选项场景时候 获取连线dom
        item.requireChild.forEach(dep => {
          if (!dep.linkDom) {
            dep.linkDom = document.getElementById(`${item.id}-link-${dep.id}`)
          }
          if (!dep.depLineDom) {
            dep.depLineDom = document.getElementById(`line${dep.id}`)
          }
        })
      }
      // console.log(cp);
      document.onmousemove = event => {
        if (event.clientX >= window.innerWidth - 40) {
          z = window.scrollX + this.currentDaySize.value
          // window.scrollTo(z, 0);
          window.scrollTo({
            top: 0,
            left: z,
            behavior: 'smooth'
          })
          newWith = event.pageX - cp
          result = this.computedList[index].left + newWith
          if (result <= 0) result = 0
          if (item.depends && item.depends.length) {
            // 拖拽有子任务选项场景
            this.handleDragSetLinkLine(result, -newWith, item.depends)
          }
          if (item.dependPid) {
            // 拖拽有父级依赖选项场景， 依据依赖id找出依赖主体的连接线并改变宽度
            let linkWidth = 0
            const dependPid = item.dependPid
            const dependPitem = this.computedList.find(from => from.id === dependPid)
            if (result <= dependPitem.left) {
              // 移动的左边距未超出父级的左边距时 不能过界
              result = dependPitem.left
              linkWidth = 0
            } else {
              linkWidth = result - (dependPitem.left - this.fromLeftDiff) - this.targetLeftDiff
            }
            dependPitem.depends.map(pItem => {
              if (pItem.id === item.id) {
                pItem.linkDom.style.width = linkWidth + 'px'
              }
            })
          }
          // 拖拽有前置依赖选项时
          if (item.requireId) {
            let linkWidth = 0
            const requireItem = this.computedList.find(req => req.id === item.requireId)
            const linkItem = requireItem.requireChild.find(link => link.id === item.id)
            let outLeft = requireItem.left + requireItem.widthMe
            if (linkItem.advanceDays && ~~linkItem.advanceDays !== 0) {
              outLeft = outLeft - ~~linkItem.advanceDays * this.currentDaySize.value
            }
            if (result <= outLeft) {
              result = outLeft
              linkWidth = 0
            } else {
              linkWidth = result - outLeft
            }
            linkItem.linkDom.style.width = linkWidth + 'px'
          }
          if (item.requireChild && item.requireChild.length) {
            // 右拖拽前置依赖的父级选项时
            item.requireChild.forEach(reqItem => {
              const targetItem = this.computedList.find(req => req.id === reqItem.id)
              let linkWidth = 0
              if (item.widthMe + result >= targetItem.left) {
                linkWidth = 0
                // 如果前置依赖父级右移过了子集的左边距则子集跟随右移
                reqItem.depLineDom.style.left = result + item.widthMe + 'px'
              } else {
                linkWidth = targetItem.left - (item.widthMe + result)
                if (item.widthMe + result >= targetItem.left) {
                  reqItem.depLineDom.style.left = result + item.widthMe + 'px'
                } else {
                  reqItem.depLineDom.style.left = targetItem.left + 'px'
                }
              }
              reqItem.linkDom.style.left = result + item.widthMe - this.reqFromLeftDiff + 'px'
              reqItem.linkDom.style.width = linkWidth + 'px'
            })
          }
          line.style.left = result + 'px'
        } else if (event.clientX <= 40 + this.rightLineX) {
          z = window.scrollX - this.currentDaySize.value
          // window.scrollTo(z, 0);
          window.scrollTo({
            top: 0,
            left: z,
            behavior: 'smooth'
          })
          newWith = event.pageX - cp
          result = this.computedList[index].left + newWith
          if (result <= 0) result = 0
          if (item.depends && item.depends.length) {
            // 拖拽有子任务选项场景
            this.handleDragSetLinkLine(result, -newWith, item.depends)
          }
          if (item.dependPid) {
            // 拖拽有父级依赖选项场景， 依据依赖id找出依赖主体的连接线并改变宽度
            let linkWidth = 0
            const dependPid = item.dependPid
            const dependPitem = this.computedList.find(from => from.id === dependPid)
            if (result <= dependPitem.left) {
              // 移动的左边距未超出父级的左边距时 不能过界
              result = dependPitem.left
              linkWidth = 0
            } else {
              linkWidth = result - (dependPitem.left - this.fromLeftDiff) - this.targetLeftDiff
            }
            dependPitem.depends.map(pItem => {
              if (pItem.id === item.id) {
                pItem.linkDom.style.width = linkWidth + 'px'
              }
            })
          }
          // 拖拽有前置依赖选项时
          if (item.requireId) {
            let linkWidth = 0
            const requireItem = this.computedList.find(req => req.id === item.requireId)
            const linkItem = requireItem.requireChild.find(link => link.id === item.id)
            let outLeft = requireItem.left + requireItem.widthMe
            if (linkItem.advanceDays && ~~linkItem.advanceDays !== 0) {
              outLeft = outLeft - ~~linkItem.advanceDays * this.currentDaySize.value
            }
            if (result <= outLeft) {
              result = outLeft
              linkWidth = 0
            } else {
              linkWidth = result - outLeft
            }
            linkItem.linkDom.style.width = linkWidth + 'px'
          }
          if (item.requireChild && item.requireChild.length) {
            // 右拖拽前置依赖的父级选项时
            item.requireChild.forEach(reqItem => {
              const targetItem = this.computedList.find(req => req.id === reqItem.id)
              let linkWidth = 0
              if (item.widthMe + result >= targetItem.left) {
                linkWidth = 0
                // 如果前置依赖父级右移过了子集的左边距则子集跟随右移
                reqItem.depLineDom.style.left = result + item.widthMe + 'px'
              } else {
                linkWidth = targetItem.left - (item.widthMe + result)
                if (item.widthMe + result >= targetItem.left) {
                  reqItem.depLineDom.style.left = result + item.widthMe + 'px'
                } else {
                  reqItem.depLineDom.style.left = targetItem.left + 'px'
                }
              }
              reqItem.linkDom.style.left = result + item.widthMe - this.reqFromLeftDiff + 'px'
              reqItem.linkDom.style.width = linkWidth + 'px'
            })
          }
          line.style.left = result + 'px'
        } else {
          newWith = event.pageX - cp
          result = this.computedList[index].left + newWith
          if (result <= 0) result = 0
          if (item.depends && item.depends.length) {
            // 拖拽有子任务选项场景
            this.handleDragSetLinkLine(result, -newWith, item.depends)
          }
          if (item.dependPid) {
            // 拖拽有父级依赖选项场景， 依据依赖id找出依赖主体的连接线并改变宽度
            let linkWidth = 0
            const dependPid = item.dependPid
            const dependPitem = this.computedList.find(from => from.id === dependPid)
            if (result <= dependPitem.left) {
              // 移动的左边距未超出父级的左边距时 不能过界
              result = dependPitem.left
              linkWidth = 0
            } else {
              linkWidth = result - (dependPitem.left - this.fromLeftDiff) - this.targetLeftDiff
            }
            dependPitem.depends.map(pItem => {
              if (pItem.id === item.id) {
                pItem.linkDom.style.width = linkWidth + 'px'
              }
            })
          }
          // 拖拽有前置依赖选项时
          if (item.requireId) {
            let linkWidth = 0
            const requireItem = this.computedList.find(req => req.id === item.requireId)
            const linkItem = requireItem.requireChild.find(link => link.id === item.id)
            let outLeft = requireItem.left + requireItem.widthMe
            if (linkItem.advanceDays && ~~linkItem.advanceDays !== 0) {
              outLeft = outLeft - ~~linkItem.advanceDays * this.currentDaySize.value
            }
            if (result <= outLeft) {
              result = outLeft
              linkWidth = 0
            } else {
              linkWidth = result - outLeft
            }
            linkItem.linkDom.style.width = linkWidth + 'px'
          }
          if (item.requireChild && item.requireChild.length) {
            // 右拖拽前置依赖的父级选项时
            item.requireChild.forEach(reqItem => {
              const targetItem = this.computedList.find(req => req.id === reqItem.id)
              let linkWidth = 0
              if (item.widthMe + result >= targetItem.left) {
                linkWidth = 0
                // 如果前置依赖父级右移过了子集的左边距则子集跟随右移
                reqItem.depLineDom.style.left = result + item.widthMe + 'px'
              } else {
                linkWidth = targetItem.left - (item.widthMe + result)
                if (item.widthMe + result >= targetItem.left) {
                  reqItem.depLineDom.style.left = result + item.widthMe + 'px'
                } else {
                  reqItem.depLineDom.style.left = targetItem.left + 'px'
                }
              }
              reqItem.linkDom.style.left = result + item.widthMe - this.reqFromLeftDiff + 'px'
              reqItem.linkDom.style.width = linkWidth + 'px'
            })
          }
          line.style.left = result + 'px'
        }
        // this.lineMouseover(dom, e, id, parentId, index)
        this.lineMouseleave(e, true)
      }
      document.onmouseup = events => {
        if (!result) {
          document.onmousemove = document.onmouseup = null
          return
        }
        left =
          Math.round(result / this.currentDaySize.value) *
          this.currentDaySize.value
        if (item.depends && item.depends.length) {
          // 拖拽有子任务选项场景
          this.handleDragSetLinkLine(left, -newWith, item.depends, true)
        }
        if (item.dependPid) {
          // 拖拽有父级依赖选项场景， 依据依赖id找出依赖主体的连接线并改变宽度
          let linkWidth = 0
          const dependPid = item.dependPid
          const dependPitem = this.computedList.find(from => from.id === dependPid)
          if (left <= dependPitem.left) {
            // 移动的左边距未超出父级的左边距时 不能过界
            left = dependPitem.left
            linkWidth = 0
          } else {
            linkWidth = left - (dependPitem.left - this.fromLeftDiff) - this.targetLeftDiff
          }
          dependPitem.depends.map(pItem => {
            if (pItem.id === item.id) {
              pItem.linkDom.style.width = linkWidth + 'px'
            }
          })
        }
        // 拖拽有前置依赖选项时
        if (item.requireId) {
          let linkWidth = 0
          const requireItem = this.computedList.find(req => req.id === item.requireId)
          const linkItem = requireItem.requireChild.find(link => link.id === item.id)
          let outLeft = requireItem.left + requireItem.widthMe
          if (linkItem.advanceDays && ~~linkItem.advanceDays !== 0) {
            outLeft = outLeft - ~~linkItem.advanceDays * this.currentDaySize.value
          }
          if (left <= outLeft) {
            left = outLeft
            result = item.widthMe + (item.left - left)
            linkWidth = 0
          } else {
            linkWidth = left - outLeft
          }
          linkItem.linkWidth = linkWidth
          linkItem.linkDom.style.width = linkWidth + 'px'
        }
        if (item.requireChild && item.requireChild.length) {
          // 右拖拽前置依赖的父级选项时
          item.requireChild.forEach(reqItem => {
            const targetItem = this.computedList.find(req => req.id === reqItem.id)
            let linkWidth = 0
            if (item.widthMe + left >= targetItem.left) {
              linkWidth = 0
              // 如果前置依赖父级右移过了子集的左边距则子集跟随右移
              reqItem.depLineDom.style.left = left + item.widthMe + 'px'
              targetItem.left = left + item.widthMe
            } else {
              linkWidth = targetItem.left - (item.widthMe + left)
            }
            reqItem.linkDom.style.left = left + item.widthMe + 'px'
            reqItem.linkDom.style.width = linkWidth + 'px'
          })
        }
        this.list[index].left = left
        line.style.left = left + 'px'
        this.checkIsin(dom, events, id, parentId, index)
        this.list.forEach(item => {
          if (item.id === id) {
            item.left = left
            item.startTime = this.computedWithTime(left)
            let end = left + item.widthMe
            end = Math.round(end / this.currentDaySize.value) * this.currentDaySize.value - this.currentDaySize.value
            item.endTime = this.computedWithTime(end)
          }
        })
        if (parentId) {
          this.setGroupWidth(parentId)
        }
        document.onmousemove = document.onmouseup = null
      }
    },
    // 鼠标离开信息消失，时间显示消失
    /**
     * @param  {Object} e $event
     * @param  {Boolean} move 是否移动状态
     */
    lineMouseleave (e, move) {
      if (move) {
        this.isShowMsg = false
        this.currentProjectMsg = {}
        // this.handlerSelect();
        return
      }
      this.currentLineDay = {
        start: 0,
        end: 0
      }
      this.isHover = false
      this.isShowMsg = false
      this.currentProjectMsg = {}
      // this.handlerSelect();
    },
    // 根据距离计算时间
    /**
     * @param  {Number} width
     * @param  {Boolean|String} time
     */
    computedWithTime (width, time) {
      const startTimeYear = new Date(this.startTime).getFullYear()
      let startYear = 0
      if (this.currentYear - 1 > startTimeYear) {
        startYear = startTimeYear
      } else {
        startYear = this.currentYear - 1
      }
      const startTime =
        (width / this.currentDaySize.value) * (1000 * 60 * 60 * 24) +
        new Date(`${startYear}/01/01`).getTime()
      const s = new Date(startTime)
      if (time && time === true) {
        return s.getTime()
      } else if (time && time === 'YD') {
        let m = s.getMonth() + 1
        m = m < 10 ? `0${m}` : m
        return `${s.getFullYear()}/${m}`
      } else {
        let m = s.getMonth() + 1
        m = m < 10 ? `0${m}` : m
        let d = s.getDate()
        d = d < 10 ? `0${d}` : d
        return `${s.getFullYear()}/${m}/${d}`
      }
    },
    // 根据时间计算left
    /**
     * @param  {String} timeStr
     */
    computedLeft (timeStr) {
      const startTimeYear = new Date(this.startTime).getFullYear()
      const startYear = this.currentYear - 1 > startTimeYear ? startTimeYear : this.currentYear - 1
      const curLeft = (new Date(timeStr).getTime() - new Date(`${startYear}/01/01`).getTime()) / (1000 * 60 * 60 * 24) * this.currentDaySize.value
      return curLeft
    },
    // 根据index值和e判断是否在当前line的范围里，是否展示时间和msg框
    /**
     * @param  {String} dom ref
     * @param  {Object} events $event
     * @param  {Number} id id
     * @param  {Number} parentId parentId
     * @param  {Number} index index
     */
    checkIsin (dom, events, id, parentId, index) {
      const line = document.getElementById(dom)
      const lineTop = parseInt(line.style.top)
      const lineDown = lineTop + 16
      const lineLeft = parseInt(line.style.left)
      const lineRight = parseInt(this.computedList[index].widthMe) + lineLeft
      if (
        events.pageX - this.rightLineX >= lineLeft &&
        events.pageX - this.rightLineX <= lineRight &&
        events.y - 40 >= lineTop &&
        events.y - 40 <= lineDown
      ) {
        // this.lineMouseover(dom, events, id, parentId, index)
        this.lineMouseenter(dom, events, id, parentId, index)
      } else {
        this.isShowMsg = false
        this.currentLineDay = {
          start: 0,
          end: 0
        }
      }
    },
    /**
     * @param  {String} dom ref
     * @param  {Object} events $event
     * @param  {Number} id id
     * @param  {Number} parentId parentId
     * @param  {Number} index index
     */
    // 鼠标进入显示当前项目的基本信息框
    lineMouseenter (dom, e, id, parentId, index) {
      const $line = document.getElementById(dom)
      const start =
        Math.round(
          parseInt($line.style.left) / this.currentDaySize.value
        ) * this.currentDaySize.value
      let end =
        parseInt($line.style.left) +
        parseInt($line.style.width)
      end =
        Math.round(end / this.currentDaySize.value) *
          this.currentDaySize.value -
        this.currentDaySize.value
      const len = Object.keys(this.fieldsAttr).length
      for (const key in this.fieldsAttr) {
        if (this.fieldsAttr[key].showToast) {
          const field = this.fieldsAttr[key]
          let obj = {}
          obj[key] = {}
          obj[key].label = field.label
          obj[key].value = this.computedList[index][key]
          this.currentProjectMsg = Object.assign(this.currentProjectMsg, obj)
          this.currentProjectMsg.left = e.pageX + 160 >= window.innerWidth ? e.pageX - 600 : e.pageX - 400
          this.currentProjectMsg.top = e.y + (len + 2) * 30 > window.innerHeight ? e.y - (len + 2) * 30 : e.y
          obj = null
        }
      }
      this.currentProjectMsg.allTime = {}
      this.currentProjectMsg.allTime.label = '持续时间'
      this.currentProjectMsg.allTime.value = (end - start) / this.currentDaySize.value + 1 + '天'
      this.isShowMsg = true
    },
    // 获取最近三年与最小年份至最大年份并集内的所以年月日
    getAllDate () {
      const startTimeYear = new Date(this.startTime).getFullYear()
      const endTimeYear = new Date(this.endTime).getFullYear()
      const tmp = [startTimeYear, endTimeYear, this.currentYear - 1, this.currentYear + 1]
      const min = Math.min.apply(null, tmp)
      const max = Math.max.apply(null, tmp)
      let obj = {}
      const arr = []
      for (let i = min; i <= max; i++) {
        arr.push(i)
      }
      arr.forEach(item => {
        obj.year = item
        obj.days = this.isLeapYear(item) ? 365 : 366
        this.allDays.push(obj)
        obj = {}
      })
      this.checkDate()
    },
    // 根据年份天数创建月份及月份天数数组
    checkDate () {
      this.allDays.forEach(item => {
        item.month = this.handleMonthDay(item.days, item.year)
      })
      this.allDays.forEach(element => {
        if (element.year === this.currentYear) {
          element.month[0][this.currentMonth].dayArr.forEach(k => {
            if (k.date === this.currentDay) {
              k.today = true
            }
          })
        }
      })
      let arr = []
      this.allDays.forEach(item => {
        arr = arr.concat(item.month)
      })
      arr.forEach(item => {
        for (var j in item) {
          this.days = this.days.concat(item[j].dayArr)
        }
      })
      this.days.forEach((item, index) => {
        item.width = (index + 1) * this.currentDaySize.value
      })
    },
    /**
     * @description 获取该月下所有的天和周的数据情况
     * @param  {Number} days 该年下天数总计
     * @param  {Number} year
     */
    handleMonthDay (days, year) {
      const arr = []
      const obj = {}
      this.monthArr.forEach(item => {
        obj[item] = {
          dayArr: [],
          weekArr: []
        }
        let ob = {}
        // 该月的天数总计
        ob.totalDay = this.checkMonthDays(item, days)
        obj[item].dayArr.push(ob)
        ob = {}
      })
      arr.push(obj)
      const s = arr[0]
      for (const item in s) {
        const num = s[item].dayArr[0].totalDay
        const tempArr = this.addNum(num, item, year)
        tempArr.forEach(keyItem => {
          if (keyItem.weekday === 1) {
            s[item].weekArr.push(keyItem.date)
          }
        })
        s[item].dayArr = []
        s[item].dayArr = tempArr
      }
      // console.log(arr)
      // debugger
      return arr
    },
    // 根据父级id设置group的宽度
    setGroupWidth (id) {
      let parentItem
      const childrenItem = []
      const that = this
      that.list.forEach(item => {
        if (item.id === id) {
          parentItem = item
        }
        if (item.parentId === id) {
          childrenItem.push(item)
        }
      })
      function fn (parent, children) {
        const left = Math.min.apply(
          Math,
          children.map(o => {
            return o.left
          })
        )
        const arrWidth = []
        children.forEach(item => {
          arrWidth.push(item.left + item.widthMe)
        })
        const width = Math.max.apply(Math, arrWidth)
        const widthMe = width - left
        parent.widthMe = parent.widthChild = widthMe
        parent.left = left
        // 如果父级还有父级递归继续
        if (parent.parentId) {
          let parentItem
          const childrenItem = []
          that.list.forEach(item => {
            if (item.id === parent.parentId) {
              parentItem = item
            }
            if (item.parentId === parent.parentId) {
              childrenItem.push(item)
            }
          })
          fn(parentItem, childrenItem)
        }
      }
      fn(parentItem, childrenItem)
    },
    // 根据月份返回天数
    /**
     * @param  {Number} month 月份
     * @param  {Number} days 天数
     */
    checkMonthDays (month, days) {
      let day
      switch (month) {
        case 1:
        case 3:
        case 5:
        case 7:
        case 8:
        case 10:
        case 12:
          return 31
          // eslint-disable-next-line no-unreachable
          break
        case 4:
        case 6:
        case 9:
        case 11:
          return 30
          // eslint-disable-next-line no-unreachable
          break
        case 2:
          day = days === 365 ? 28 : 29
          return day
          // eslint-disable-next-line no-unreachable
          break
      }
    },
    /**
     * @description 获取月份下所有天的日期和星期几
     * @param  {number} num 天数
     * @param  {number} month 月份
     * @param  {number} year 年份
     */
    addNum (num, month, year) {
      const arr = []
      let obj = {}
      const quarterArr = [1, 4, 7, 10]
      const halfYearArr = [1, 7]
      for (let i = 1; i <= num; i++) {
        if (quarterArr.includes(~~month) && i === 1) {
          // 季度开始日/分割线
          obj.quarterStrat = true
        }
        if (halfYearArr.includes(~~month) && i === 1) {
          // 半年开始日/分割线
          obj.halfYearStrat = true
        }
        obj.year = year
        obj.month = ~~month
        obj.date = i
        obj.weekday = new Date(`${year}/ ${month} / ${i}`).getDay()
        arr.push(obj)
        obj = {}
      }
      return arr
    },
    // 判断是否为闰年
    /**
     * @param  {Number} year 传入年份
     */
    isLeapYear (year) {
      if (year % 4 > 0) {
        return true
      }
      return false
    },
    // 更改daySize
    handleSetDaySize (item) {
      this.currentDaySize = item
      this.days.forEach((item, index) => {
        item.width = (index + 1) * this.currentDaySize.value
      })
      this.handleScroll()
      if (this.currentRow) {
        const rs = this.computedList.find(o => {
          return o.id === this.currentRow.id
        })
        this.$nextTick(() => {
          window.scrollTo(rs.left - 100, 0)
        })
      }
    },
    // 回到今天
    handleGoToday () {
      const s =
        Math.round(window.innerWidth / this.currentDaySize.value / 2) *
          this.currentDaySize.value -
        this.rightLineX
      const width =
        (Math.floor(
          new Date(
            `${this.currentYear}/${this.currentMonth}/${this.currentDay}`
          ).getTime() - new Date(`${this.currentYear - 1}/01/01`).getTime()
        ) /
          (1000 * 60 * 60 * 24)) *
          this.currentDaySize.value -
        s
      window.scrollTo({
        top: 0,
        left: width,
        behavior: 'smooth'
      })
    },
    // 顶部固定时间
    handleScroll () {
      const w = window.scrollX
      if (w <= 62) {
        this.showFixdTopMonth = false
      } else {
        this.showFixdTopMonth = true
      }
      const time = this.computedWithTime(w, 'YD')
      this.fixdTopMonth = time
    },
    handlerBGScroll (e) {
      this.$emit('handlerBGScroll', e)
    }
  }
}
</script>

<style lang="stylus" scoped>
.gatt-date{
  width: 100%;
  height: 100%;
  &-toolTip{
    position: fixed;
    right: 0px;
    top: 82px;
    z-index: 999;
    .base{
      display: inline-block;
      text-align: center;
      height: 30px;
      line-height: 30px;
      padding: 0 15px;
      background-color: #fff;
      font-size: 14px;
      cursor: pointer;
      user-select: none;
      transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
      font-weight: 400;
      color: #303030;
      border-radius: 3px;
      box-shadow: 0 3px 12px 0 rgba(48, 48, 48, 0.05),
        0 3px 6px 0 rgba(48, 48, 48, 0.1);
      margin-right: 20px;
      &:hover{
        color: #409eff;
      }
    }
  }
  .projectMsg{
    box-sizing: border-box;
    padding: 20px;
    position: absolute;
    z-index: 99;
    min-width:180px;
    background-color: rgba(0,0,0,0.5);
    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
    border-radius: 4px;
    .lineMsg{
      margin-bottom: 10px;
      .projectName{
        font-size: 16px;
      }
      span{
        font-size: 12px;
        color: #fff;
      }
      .title{
        margin-right: 10px;
      }
    }
  }
}
</style>
